# -*- coding: utf-8 -*-
import asyncio
import uuid
import cv2
import oss2
from flask import Flask, render_template, request, jsonify
from werkzeug.utils import secure_filename
from auth import auth_login, require_login
from light import *

app = Flask(__name__)

workspace_id = os.environ['WORKSPACE_ID']
endpoint = os.environ['OSS_ENDPOINT']
auth = oss2.Auth(os.environ['ALIBABA_CLOUD_ACCESS_KEY_ID'], os.environ['ALIBABA_CLOUD_ACCESS_KEY_SECRET'])
bucket = oss2.Bucket(auth, endpoint, os.environ['OSS_BUCKET'])

app.config['UPLOAD_FOLDER'] = './'



def get_param(url, work_space_id, prompt):
    run_video_analysis_param = "{\"generateOptions\":[\"videoAnalysis\",\"videoGenerate\"],\"videoModelCustomPromptTemplate\":\"# 角色\\n你是一名视频分析师，擅长对各种视频片段进行理解。\\n\\n# 任务描述\\n给你一个视频片段的多张关键帧图片，请你完成以下任务。\\n- 输出每张图片的画面信息，包括人物、物体、动作、文字、字幕、镜头语言、一句话总结等。\\n- 把每张图片的信息串联起来，生成视频的详细概述，还原该片段的剧情。\\n\\n# 限制\\n- 分析范围严格限定于提供的视频子片段，不涉及视频之外的任何推测或背景信息。\\n- 总结时需严格依据视频内容，不可添加个人臆测或创意性内容。\\n- 保持对所有视频元素（尤其是文字和字幕）的高保真还原，避免信息遗漏或误解。\\n\\n# 输入数据\\n## 视频片段ASR信息  (如果输入为空则忽略ASR信息)\\n{videoAsrText}\\n\\n## 视频补充信息 (可能对你理解该片段有帮助，如果输入为空则忽略补充信息)\\n{videoExtraInfo}\\n\\n## 视频片段中出现的角色信息 (如果输入为空则忽略)\\n{rolesText}\\n\\n# 输出格式\\n直接按照任务目标里即可，先输出每张图片的描述，再串联起来输出整个视频片段的剧情。\",\"textProcessTasks\":[{\"modelId\":\"qwen-max-latest\",\"modelCustomPromptTemplate\":\"# 角色\\n你是一个专业的视频标注专员，擅长结合视频镜头信息来分析处理各种视频任务。\\n\\n# 任务目标\\n请你结合输入数据串联、还原出整个视频的详细剧情。\\n\\n# 限制\\n1.如出现语法上错误，或逻辑不通，请直接修改\\n2.在视频分镜中，如果包含台词，可能会出现说话者与其所说内容不匹配的情况。因此，必须根据剧情的进展，准确判断每段台词的真实说话者\\n3.如果视频分镜中无台词，请根据视频音频文字为其匹配台词\\n4.修改后的故事请适当保留视频分镜中对人物、场景的描写\\n5.帮忙润色一下故事，使其更具逻辑性\\n6.结合视频分镜中的人物外观特点，如果有外观相近的人物是同一个角色。因此，需要将不同分镜中的人物角色统一。\\n\\n# 输入数据\\n## 资料一：视频分镜信息 (视频各镜头的视觉描述信息)\\n{videoAnalysisText}\\n\\n## 资料二：视频ASR转录信息 (未标注出说话者，可能有错误和遗漏，如果没有输入ASR，则忽略此信息)\\n{videoAsrText}\\n\\n## 资料三：视频补充信息 (如果输入为空则忽略补充信息)\\n{videoExtraInfo}\\n\\n# 输出格式\\n直接输出视频剧情，不要输出其他信息。\"}],\"videoModelId\":\"qwen-vl-max-latest\",\"language\":\"chinese\",\"frameSampleMethod\":{\"methodName\":\"standard\"}}"
    param_dict = json.loads(run_video_analysis_param)
    param_dict["workspaceId"] = work_space_id
    param_dict["videoUrl"] = url
    param_dict["videoExtraInfo"] = prompt
    new_run_video_analysis_param = json.dumps(param_dict, ensure_ascii=False)
    return new_run_video_analysis_param
def get_video_info(video_path):
    """获取视频帧数和帧率"""
    cap = cv2.VideoCapture(video_path)
    if not cap.isOpened():
        return None, None
    frame_count = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
    fps = cap.get(cv2.CAP_PROP_FPS)
    cap.release()
    return frame_count, fps



@app.route('/login', methods=['POST', 'GET'])
def login():
    return auth_login()


@app.route('/', methods=['GET'])
@require_login
def index():
    return render_template('index.html')


@app.route('/api/upload', methods=['POST'])
@require_login
def handle_upload():
    if 'file' not in request.files:
        return jsonify({"error": "No file part"}), 400

    file = request.files['file']
    if file.filename == '':
        return jsonify({"error": "No selected file"}), 400

    allowed_extensions = {'mp4'}
    ext = secure_filename(file.filename).split('.')[-1].lower()
    if ext not in allowed_extensions:
        return jsonify({"error": f"不支持该文件格式: {ext}"}), 448

    # 创建临时目录
    temp_dir = os.path.join(app.config['UPLOAD_FOLDER'], 'temp')
    os.makedirs(temp_dir, exist_ok=True)
    temp_filename = f"{uuid.uuid4().hex}.{ext}"
    temp_path = os.path.join(temp_dir, temp_filename)

    try:
        max_duration = 10 * 60
        file.save(temp_path)

        frame_count, fps = get_video_info(temp_path)
        duration = frame_count / fps
        if duration > max_duration:
            return jsonify({"error": f"视频时长超过{max_duration}秒"}), 447

        object_name = f"{uuid.uuid4().hex}.{ext}"
        with open(temp_path, 'rb') as f:
            result = bucket.put_object(object_name, f)

        if result.status != 200:
            return jsonify({"error": "OSS上传失败"}), 500

        url = bucket.sign_url('GET', object_name, 3600 * 24)
        data = {'video_url': url}
        return jsonify({'code': 200, 'data': data})

    except Exception as e:
        return jsonify({'error': str(e)}), 500
    finally:
        # 清理临时文件
        if os.path.exists(temp_path):
            try:
                os.remove(temp_path)
            except:
                pass



@app.route('/api/completions', methods=['POST'])
@require_login
def handle_completions():
    try:
        data = request.json
        if not isinstance(data, dict):
            return jsonify({"error": "Invalid request data format"}), 400

        keyframe = data.get('video_url')
        if not keyframe:
            return jsonify({"error": "Missing 'video_url' in request data"}), 420

        prompt = data.get('prompt', '')
        run_video_analysis_param = get_param(keyframe, workspace_id, prompt)

        light_app = LightApp()
        try:
            description = asyncio.run(light_app.run_video_analysis(run_video_analysis_param))
        except Exception as e:
            return jsonify({'error': str(e)}), 403
        return jsonify({'code': 200, 'data': description})
    except Exception as e:
        return jsonify({'error': str(e)}), 500




if __name__ == "__main__":
    app.run(host='0.0.0.0',port=9000)
